home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-29 | 49.9 KB | 1,299 lines |
-
-
-
-
- MAXLIB.DOC
- ─────────────────────────────────
- Documentation for MAXLIB For PB
-
-
-
-
-
-
-
-
-
-
- Copyright 1994 Brian McLaughlin
- ────────────────────────────────────────────
- All Rights Reserved
-
-
-
-
-
-
-
- TABLE OF CONTENTS
-
- line number
-
- INTRODUCTION ....................................... 62
-
- About This Document ........................... 105
- MAXLIB For PB is Shareware .................... 124
- PBFiles is Yours - Free! ...................... 158
- Requirements for Using MAXLIB For PB .......... 191
- Limited Warranty .............................. 227
-
-
- HOW TO USE MAXLIB FOR PB
-
- Using $LINK and $INCLUDE ...................... 265
- Using MAXLIB in the IDE ...................... 310
- Getting Started with MAXFiles ................. 340
- Getting Started with MAXArray ................. 537
- Handling Errors ............................... 711
-
-
- GENERAL TOPICS
-
- About File Pointers ........................... 852
- About Expanded Memory ......................... 967
- About DOS STDxxx Devices ...................... 1040
- Avoiding Problems With HUGE Arrays ............ 1116
- Safeguarding Your Data ........................ 1218
-
-
-
-
-
- INTRODUCTION
-
-
- MAXLIB For PB is designed to make your programs faster and more
- capable than ever before. And because MAXLIB For PB builds upon
- familiar BASIC commands and ideas, it is easy to learn and easy
- to incorporate into your code.
-
- MAXLIB for PB consists of two complete sets of routines:
- MAXFiles and MAXArray. Both of them provide you with easy, but
- sophisticated memory management. Each one presents you with a
- different interface and its own set of strengths, so you can
- choose the one that best suits your needs.
-
- The 25 commands in MAXFiles are patterned after the BASIC
- commands used with disk files (especially files opened for
- binary access). MAXFiles speeds up your program's disk file
- access by loading disk files into expanded memory as they are
- opened. From then on, your program will read from and write to
- the file in expanded memory, which is much faster than if the
- file were accessed directly from the disk.
-
- MAXFiles takes advantage of whatever expanded memory is
- available (if any) and will automatically fall back to using
- disk space when expanded memory is exhausted. For that reason,
- programs written using MAXFiles can run on computers with no
- expanded memory, or with very little, or a lot -- all using the
- same few lines of code!
-
- The 16 commands in MAXArray are patterned after the BASIC
- commands used to dimension and manage arrays in conventional
- memory. With MAXArray you can create and manage arrays that are
- much larger than 640K, right up to the limit of available EMS
- memory, without having to learn all the intricacies of expanded
- memory management.
-
- MAXArray lets you copy entire files or conventional arrays into
- and out of expanded memory using a single line of code! And
- because it has less internal complexity, MAXArray is even faster
- than MAXFiles.
-
-
-
- ABOUT THIS DOCUMENT
-
-
- This file (MAXLIB.DOC) discusses topics of general interest to
- anyone using MAXLIB For PB. Technical details for each routine
- are available in the file MAXLIB.REF.
-
- In this document the terms "expanded memory" and "EMS" are used
- (somewhat loosely) to mean the same thing.
-
- In this document the term "EMS file" refers to a file loaded
- into expanded memory and being accessed there, as opposed to a
- file that is located on a disk drive. The term "EMS array"
- refers to an array stored in expanded memory and accessed there,
- as opposed to an array stored in conventional memory.
-
-
-
-
- MAXLIB FOR PB IS SHAREWARE
-
-
- MAXLIB For PB is shareware. It is not free software. You are
- expected to pay for MAXLIB For PB, if you decide to keep it and
- use it.
-
- Shareware may be freely copied and distributed, eliminating the
- high distribution costs associated with most commercial
- software. The shareware method also allows you to evaluate
- whether MAXLIB For PB meets your needs and does what it is
- supposed to do, before you pay for it.
-
- Programs you write using this evaluation copy of MAXLIB For PB
- must be for the purpose of evaluation only. Under no
- circumstances are you allowed to compile and distribute programs
- incorporating MAXLIB For PB, unless you have the appropriate
- license. To obtain an appropriate license you must register
- MAXLIB For PB.
-
- All the information you need in order to register MAXLIB For PB,
- including what it costs and what you get when you register, is
- contained in the file REGISTER.TXT. You'll find an easy to
- print order form in the file ORDER.FRM.
-
- MAXLIB For PB represents the end product of hundreds of hours of
- skilled labor, spent in designing, programming, testing and
- documentation. I believe MAXLIB For PB will meet your
- professional standards and that it compares well to any
- programming library of its kind. I hope you agree.
-
-
-
-
- PBFILES IS YOURS - FREE!
-
-
- As part of the package distributed with MAXLIB For PB, you will
- find a file called PBFILES.ZIP. It contains the source code,
- object file and documentation for a file i/o library called
- PBFiles. PBFiles is functionally identical to MAXFiles, except
- it has no support for emulated file i/o in expanded memory.
-
- I have placed the source code for PBFiles into the public
- domain. That means PBFiles is free for you to use as you wish.
- It requires no payment or fees of any kind. PBFILES.ZIP also
- includes PBFILES.DOC, a copyrighted file you may freely
- distribute.
-
- The only conditions I have placed on copying PBFILES.DOC is that
- it must not be altered, and it must always be accompanied by
- unaltered copies of the source code file and two other files.
-
- I wrote PBFiles and included it with MAXLIB For PB so that the
- code you write for the purpose of evaluating MAXFiles will
- remain useful, even if you decide not to register MAXLIB. This
- should adequately compensate you for the time and effort you
- spend in evaluating MAXLIB For PB.
-
- It is simple to convert any code you have written for MAXFiles
- to use PBFiles instead. If you change your mind later and
- decide to register MAXLIB For PB, all the code you wrote using
- PBFiles will painlessly convert back for use with MAXLIB For PB.
-
-
-
-
- REQUIREMENTS FOR USING MAXLIB FOR PB
-
-
- To use MAXLIB For PB you must have a copy of the PowerBASIC 3.0b
- compiler or later. I have tested MAXLIB For PB with the
- PowerBASIC 3.0a release and found that because of bugs in that
- compiler, MAXLIB For PB is not stable.
-
- You must also have a copy of the library file MAXLIB.PBL which
- is included as part of MAXLIB For PB.
-
- MAXLIB is written in 8086 assembly language and should run on
- any 80x86-based computer. MAXLIB only uses DOS functions that
- are present in every version of DOS numbered v2.1 and later.
-
- The MAXFiles portion of MAXLIB For PB is designed to operate
- with or without expanded memory, but it requires the presence of
- an EMM driver v4.0 (or better) for the EMS features to be
- active.
-
- The MAXArray portion of MAXLIB For PB requires the presence of
- expanded memory. MAXArray should work with all versions of EMM
- driver software numbered v3.0 and later.
-
- NOTE: Although MAXLIB For PB includes some support for networks,
- it has not been tested in a networked environment. If you
- intend to use MAXLIB For PB on a network, you should test your
- code thoroughly to ensure it is network-safe.
-
- PowerBASIC is a trademark of PowerBASIC, Inc of Carmel,
- California.
-
-
-
-
-
- LIMITED WARRANTY
-
-
- THIS COPY OF MAXLIB FOR PB (THE "SOFTWARE") IS PROVIDED ON AN
- "AS IS" BASIS. BRIAN MCLAUGHLIN (THE "AUTHOR") DISCLAIMS ALL
- WARRANTIES RELATING TO THE SOFTWARE, WHETHER EXPRESSED OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF
- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NEITHER
- THE AUTHOR NOR ANYONE ELSE WHO HAS BEEN INVOLVED IN THE
- CREATION, PRODUCTION, OR DELIVERY OF THE SOFTWARE SHALL BE
- LIABLE FOR ANY INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES
- ARISING OUT OF THE USE OR INABILITY TO USE SUCH SOFTWARE, EVEN
- IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGES OR CLAIMS. THE PERSON USING THE SOFTWARE BEARS ALL RISK
- AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE.
-
- This agreement shall be governed by the laws of the State of
- Oregon and shall inure to the benefit of the author and any
- successors, administrators, heirs and assigns. Any action or
- proceeding brought by either party against the other arising out
- of or related to this agreement shall be brought only in a STATE
- or FEDERAL COURT of competent jurisdiction located in Clackamas
- County, OR. The parties hereby consent to in personam
- jurisdiction of said courts.
-
-
-
-
-
- HOW TO USE MAXLIB FOR PB
-
-
- This section contains enough information to get you started
- using MAXLIB For PB. More detailed information is available in
- the file MAXLIB.REF.
-
-
-
- USING $LINK AND $INCLUDE
-
-
- Every program that uses MAXLIB For PB must meet a few simple
- requirements: it must make the library file MAXLIB.PBL available
- to the PB compiler, and it must include declarations for all the
- routines it uses from MAXLIB For PB.
-
- By far the easiest way to meet these requirements is to add two
- simple lines of code near the beginning of your source code.
- The first line uses the $LINK metacommand to incorporate
- MAXLIB.PBL into your program. You must place this line before
- any executable commands in your source code:
-
-
- $LINK "MAXLIB.PBL"
-
-
- If MAXLIB.PBL is not in the current directory, you must tell PB
- how to find it by including the full path in the the file spec.
- For instance, if MAXLIB.PBL were on a RAM disk designated as
- your D: drive, in a subdirectory named LIB, the full file spec
- would be:
-
-
- $LINK "D:\LIB\MAXLIB.PBL"
-
-
- You will also need to include a second line near the top of your
- source code:
-
-
- $INCLUDE "MAXLIB.BI"
-
-
- MAXLIB.BI contains the declarations for all the routines in
- MAXLIB For PB. The above line of code above includes those
- declarations in your code. Again, if MAXLIB.BI is not in the
- current directory, you will need to let PB know how to find it
- by including the full path in the file spec.
-
-
-
-
-
- USING MAXLIB IN THE IDE
-
-
- If you program within the PowerBASIC IDE (called PB.EXE), you
- should realize that the IDE, by default, uses all the EMS
- resources on your computer.
-
- If you do not change this default behavior, there will not be
- any expanded memory available to your programs that use MAXLIB,
- when you compile them and test them from inside the IDE. With
- no EMS to work with, commands in MAXFiles will always fall back
- to disk access and commands in MAXArray will not work at all.
-
- The same problems apply to running your programs under PBD.EXE.
-
- To change the defaults for PB.EXE or PBD.EXE, you must run
- PBINST.EXE. Choose the menu item "Limit EMS/XMS usage". You
- must choose an amount of EMS other than "ALL".
-
- NOTE: If you use EMM386.SYS or another memory manager that uses
- upper memory to simulate both XMS and EMS memory, then you must
- also use PBINST.EXE to limit XMS usage to an amount other than
- "ALL". If you do not, no EMS memory will be available to your
- program, even if you limit EMS usage to zero.
-
-
-
-
-
-
- GETTING STARTED WITH MAXFILES
-
-
- The information in this section is designed to get you started
- with MAXFiles. Consult MAXLIB.REF to get answers to specific
- questions about how each routine works.
-
- Disk access is the slowest operation on any computer. Access to
- memory is one of the fastest. MAXFiles is designed to speed up
- your programs by transferring as many disk operations as
- possible from the disk drive into expanded memory.
-
- MAXFiles is simple to learn. You open or create the files you
- want to work with and read from them or write to them using a
- set of routines that are very similar to the file commands you
- would use with OPEN FOR BINARY files in PB.
-
- Here's a list of the MAXFiles routines that have close
- counterparts in PowerBASIC:
-
-
- OpenX% ................ OPEN (...FOR BINARY)
- SetAccessCode ......... ACCESS LOCK/UNLOCK/READ/WRITE, etc.
- CloseX ................ CLOSE# (close one open file)
- ClearX ................ CLOSE (close all open files)
- PutX .................. PUT (as a file statement)
- GetX .................. GET (as a file statement)
- PutStX ................ PUT$
- GetStX ................ GET$
- SaveX ................. BSAVE
- LoadX ................. BLOAD
- GetLineX$ ............. LINE INPUT#
- EndX% ................. EOF (used only with GetLineX$)
- GetLocX& .............. SEEK (as a function)
- SetLocX ............... SEEK (as a statement)
- SizeX& ................ LOF
- KillX ................. KILL
- FlushX ................ FLUSH
- ErrorCode% ............ ERR
- SetErrorCode .......... ERROR
- SetPtrBase ............ OPTION BASE
-
-
-
- MAXFiles also includes the following commands that have no close
- equivalent in BASIC:
-
-
- InitMAXFiles .......... initializes MAXFiles
- ClipX ................. truncates a file
- GetPtrBase% ........... returns value set by SetPtrBase
- HandleX% .............. returns latest handle opened
- SaveLineX ............. allows GetLineX to read multiple files
- SetBufferSize ......... sets size of buffer used by GetLineX
- SetDiskFile ........... (dis/en)ables use of EMS memory
-
-
-
- To use MAXFiles, you must call InitMAXFiles once, before you
- call any other routines. If you do not, MAXFiles will not use
- EMS, but will only use ordinary disk i/o. Typically, the top
- few lines of a program using MAXFiles look like this:
-
-
- $LINK "MAXLIB.PBL" 'include the MAXLIB library
- $INCLUDE "MAXLIB.BI" 'include the declarations file
- InitMAXFiles 'initialize MAXFiles
-
-
- Among other things, InitMAXFiles determines what sort of EMM
- driver is on the host machine. If there is no EMM driver, or if
- the driver has a version number prior to v4.0, the files you
- open with MAXFiles will be ordinary disk files.
-
- As with BASIC, with MAXFiles you must open files before you can
- use them. To open a file, you use the command OpenX%. The
- command looks like this:
-
-
- FileSpec$ = "D:\SUBDIR\FILENAME.EXT"
- Handle% = OpenX%(FileSpec$)
-
-
- If there is enough expanded memory to hold the entire file,
- OpenX% copies the file into expanded memory and returns a handle
- for the file, similar to a file number in BASIC.
-
- On the other hand, if there isn't any expanded memory on the
- host machine, or if there isn't enough to hold the entire file,
- OpenX% opens the file as a disk file and passes the DOS file
- handle back to your program.
-
- You MUST keep track of the handle OpenX% returns. You will
- refer to the file using this handle, in much the same way you
- refer to a file opened in BASIC by its file number.
-
- Once a file is opened, you can use other commands from MAXFiles
- to read from it or write to it, get its size, find its pointer,
- move its pointer, or close it.
-
- Here's an example. Suppose you want to open a file full of long
- integers and read individual long integers from it, as randomly
- requested by the user. The following code shows how that might
- look in BASIC:
-
-
- FileName$ = "C:\DATA\LONGINT.DAT" ' set file spec
- FileNum% = FREEFILE ' get file number
- OPEN FileName$ FOR BINARY AS FileNum% ' open the file
- Bytes& = LOF(FileNum%) ' get the size
- NumRecords% = Bytes& \ 4 ' calculate records
-
- DO
- LINE INPUT "Enter record number: "; Record$
- IF LEN(Record$) = 0 THEN EXIT LOOP
- RecordNum% = VAL(Record$) - 1 ' convert to zero-based
-
- SEEK FileNum%, (RecordNum% * 4) ' set the pointer
- GET FileNum%, , RecordVal& ' get the value
- PRINT "That record is" ; RecordVal& ' report it
- LOOP
-
- CLOSE FileNum% ' close file
-
-
-
- Here is the same code, written for MAXFiles:
-
-
-
- FileName$ = "C:\DATA\LONGINT.DAT" ' set file spec
- FileNum% = OpenX%(FileName$) ' open the file
- Bytes& = SizeX&(FileNum%) ' get the size
- NumRecords% = Bytes& \ 4 ' calculate records
-
- DO
- LINE INPUT "Enter record number: "; Record$
- IF LEN(Record$) = 0 THEN EXIT LOOP
- RecordNum% = VAL(Record$) - 1 ' convert to zero-based
-
- SetLocX FileNum%, (RecordNum% * 4&) ' set the pointer
- GetX FileNum%, 4&, RecordVal& ' get the value
- PRINT "That record is" ; RecordVal& ' report it
- LOOP
-
- CloseX FileNum% ' close file
-
-
- You can see how closely the two examples resemble one another.
-
- As a rule, MAXFiles treats files as binary files, but there is
- one obvious exception to this rule: text files. Because they
- are difficult to read using purely binary methods, MAXFiles
- includes the command GetLineX$, for reading text files one line
- at a time, like BASIC's LINE INPUT# command. It comes with its
- own substitute for EOF, too, called EndX%.
-
- You call GetLineX$ in a loop, like this:
-
-
- Handle% = OpenX%("TEXTFILE.TXT")
- DO
- TextArray$(X%) = GetLineX$(Handle%)
- INCR X%
- LOOP UNTIL EndX%
-
-
- Reading a text file is just that simple.
-
- Normally, when you append data to an EMS file there will be
- enough expanded memory to hold it. But sometimes there simply
- won't be any more expanded memory available to hold the new
- data. In those cases, MAXFiles will convert the EMS file to a
- disk file, on the fly.
-
- IMPORTANT: When MAXFiles converts an EMS file into a disk file
- on the fly, the value of the Handle% variable will be changed,
- too. From then on, all references to the file must use the new
- value in Handle%. This may cause problems if your program
- maintains secondary copies of the Handle% variable.
-
- Overall, if you are comfortable with binary file handling in
- BASIC, you should have no trouble adapting to MAXFiles. Even
- so, one topic where you might need extra guidance is error
- handling with MAXFiles. For more information, see the chapter
- on HANDLING ERRORS.
-
- If you are not familiar with binary file handling and file
- pointers, see the chapter ABOUT FILE POINTERS.
-
- Lastly, before you use MAXFiles to read from or write to HUGE
- arrays, you should read the chapter AVOIDING PROBLEMS WITH HUGE
- ARRAYS.
-
-
-
-
- GETTING STARTED WITH MAXARRAY
-
-
- The information in this section is designed to get you started
- with MAXArray. Consult MAXLIB.REF to get answers to specific
- questions about how each routine works.
-
- Arrays are a central part of most programs. They are easy to
- create and fast to access. But sometimes you want to make more
- arrays or larger arrays than will fit in conventional memory.
- MAXArray can help to solve those problems.
-
- MAXArray is simple to use. You create the arrays you want to
- work with and read from them or write to them using a set of
- routines that are very similar to the commands you would use to
- manipulate arrays in BASIC.
-
- Using MAXArray you can create arrays in expanded memory in which
- you can store or retreive numeric or TYPE variables, as well as
- fixed-length string variables. However, MAXArray cannot store
- or retrieve variable length strings or flex strings.
-
- Here's a list of the MAXFiles routines that have close
- counterparts in PowerBASIC:
-
-
- DimEMS% ............... DIM
- InEMS ................. Array(Index) = Variable
- OutEMS ................ Variable = Array(Index)
- EraseEMS .............. ERASE
- RedimEMS .............. REDIM
- LBoundEMS% ............ LBOUND
- UBoundEMS% ............ UBOUND
- BytesFreeEMS& ......... FRE
- ErrorCode% ............ ERR
- SetErrorCode .......... ERROR
-
-
- In addition, MAXArray has many routines that have no counterpart
- in ordinary BASIC.
-
-
- InitMAXArray .......... initializes MAXArray routines
- ArrayInEMS ............ copies conventional array to EMS
- ArrayOutEMS ........... copies EMS to conventional array
- ClearEMS .............. erases/deallocates all EMS arrays
- FileInEMS ............. copies entire file to EMS array
- FileOutEMS ............ copies entire EMS array to file
- HandlesEMS% ........... returns max number of undimmed arrays
- VersionEMS% ........... returns version number of EMM driver
-
-
- To use MAXArray you must call InitMAXArray once, before you call
- any other routines. Unless you call InitMAXArray the routines
- in MAXArray cannot function.
-
- Typically, the top few lines of a program using MAXArray look
- like this:
-
-
- $LINK "MAXLIB.PBL" 'include the MAXFiles OBJ code
- $INCLUDE "MAXLIB.BI" 'include the declarations file
- InitMAXArray 'initialize MAXArray
-
-
- The next step in using MAXArray is to dimension an array and
- put data into it. Suppose you want to dimension an array of 100
- double precision numbers, and set the value of the 100th element
- to 2.77777. Your code might look like this in BASIC:
-
-
- DIM DoubleArray# (1 TO 100) ' dim array
- DblVal# = 2.77777
- DoubleArray#(100) = DblVal# ' set value
-
-
- Here's the same code written using MAXArray:
-
-
- DoubleArray% = DimEMS%(1, 100, 8) ' dim array
- DblVal# = 2.77777
- InEMS DoubleArray%, 100, DblVal# ' set value
-
-
- As you see, to dimension an EMS array using DimEMS you must know
- the length (in bytes) of the elements of the array you are
- dimensioning.
-
- With ordinary BASIC you do not need to know that each element in
- a double precision array takes 8 bytes of storage space. DimEMS
- requires this information. Luckily, you can write code that
- this information very simply, by using the LEN command.
-
- Most BASIC programmers know that LEN will return the length of a
- string. Many of them do not know that LEN can be used with
- variables other than strings. For instance:
-
-
- DblLen% = LEN(DblVar#)
-
-
- In this example, DbleLen% will equal 8, which is the number of
- bytes needed to store a double precision variable. LEN also
- works with TYPE variables, fixed length strings and all numeric
- variables.
-
- In ordinary BASIC, you identify an array by its name. In
- MAXArray, you identify an array by the handle passed back to
- your program by DimEMS. To give your array a name, just give
- the handle variable the same name you want to give to the array.
-
- To assign a value to an array element in MAXFiles, you use
- InEMS. To assign a value to a variable from an array element,
- you use OutEMS. I have given the order of the parameters in
- each of these commands the same order as their counterpart code
- in BASIC, to help you remember. Here's how they compare:
-
-
- Variable = ArrayName(Element) 'BASIC
- OutEMS Variable, ArrayHandle, Element 'MAXArray
-
- ArrayName(Element) = Variable 'BASIC
- InEMS ArrayHandle, Element, Variable 'MAXArray
-
-
- Once you know how to dimension arrays in EMS using DimEMS, and
- how to store or retrieve values in those arrays using InEMS and
- OutEMS, you know enough to start using MAXArray. But there is
- more.
-
- To erase an array when it is no longer needed, use the command
- EraseEMS. To erase every array you have dimensioned, all at
- once, use the command ClearEMS. In most cases, this command
- (ClearEMS) will also be called automatically as your program
- ends, so you won't need to worry about deallocating the EMS
- memory your program has allocated through MAXArray.
-
- If you discover that the array you have dimensioned is too small
- or too large to hold the data you want to store, you can use
- RedimEMS to make the array larger (or smaller) without erasing
- it. Unlike the REDIM command in PowerBASIC, data in the EMS
- arrays you redimension will be preserved.
-
- MAXArray also provides routines to help you determine whether or
- not sufficient EMS resources are available to meet your needs.
- These routines are functions, called BytesFreeEMS, HandlesEMS
- and VersionEMS.
-
- VersionEMS% returns a zero when there is no EMM driver
- installed. Otherwise it returns the driver's version number as
- an integer, where 40 means version 4.0.
-
- BytesFreeEMS& returns a long integer telling how many bytes of
- EMS memory are currently unallocated and available to use.
-
- HandlesEMS% returns the number of unused handles in an internal
- table maintained by MAXArray. You can only dimension as many
- arrays as there are handles, and when HandlesEMS% returns a zero
- you can't dimension another array unless you erase another array
- that is already dimensioned.
-
- You can also use MAXArray to copy entire arrays to or from files
- or to and from conventional memory. To learn how, consult the
- entries for FileinEMS/FileOutEMS and ArrayInEMS/ArrayOutEMS in
- MAXLIB.REF.
-
- This short introduction should give you enough information to
- get started with MAXArray. I also recommend that you read the
- chapters HANDLING ERRORS, and AVOIDING PROBLEMS WITH HUGE
- ARRAYS.
-
-
-
-
- HANDLING ERRORS
-
-
- The usual method of error handling in BASIC requires that you
- use some variation of the ON ERROR statement. I have always
- found ON ERROR to be cumbersome, code-bloating and difficult to
- program. Even PowerBASIC's own manual (p.288) suggests that you
- consider using a third party library.
-
- I think you will find the error trapping in MAXLIB to be simple
- to understand and easy to use. Whenever an error takes place
- (including critical errors), the MAXLIB routine that was running
- at the time of the error will store the error code in an
- internal variable and return directly to your program.
-
- Your program must test the value of the error code variable in
- order to find out whether an error has occured. MAXFiles and
- MAXArray share a single routine for reporting the value of
- the error code variable. Reasonably enough, the routine is
- called ErrorCode%.
-
- The process of testing the value of an error code variable is
- called polling.
-
-
- Handle% = OpenX%(FileName$)
- IF ErrorCode% THEN CALL HandleError...
-
-
- In the above example, the code polls for an error directly after
- opening a file, and if ErrorCode% reports an error the code
- calls a SUB named HandleError.
-
- You can poll for errors as often or as seldom as you think
- necessary. If an error takes place in one MAXLIB routine and
- your program calls several more routines before polling for an
- error, the value of the error code variable will report the most
- recent error to take place.
-
- The internal error code variable is initialized to zero only
- once, at the beginning of your program. Its value will remain
- zero so long as no error takes place.
-
- However, when the first error takes place, the value of the
- variable will change to reflect the error code, and it will
- remain unchanged until one of two things intervenes to change
- its value:
-
- 1) another (different) error takes place, or
- 2) your program resets the value, using SetErrorCode
-
-
- SetErrorCode is similar to the function ERROR in BASIC. You may
- use it to clear the error code variable back to zero like this:
-
-
- SetErrorCode 0
-
-
- SetErrorCode may also be used to simulate errors (for example,
- during the testing of your error handler) by passing non-zero
- values corresponding to error codes. Then ErrorCode% will
- report these values back to your program as errors:
-
-
- SetErrorCode 2
- IF ErrorCode% THEN .... 'ErrorCode% always returns 2 here
-
-
- A list of error codes and what they mean can be found in the
- file ERRCODE.LST. It includes descriptions of several
- non-standard error codes that might be returned by MAXLIB
- routines. (They are: -1 through -4.)
-
- Because MAXLIB For PB requires your program to poll for errors,
- the error handling in MAXLIB For PB is roughly the same as ON
- ERROR RESUME NEXT used with ERR, in this fashion:
-
-
- ON ERROR RESUME NEXT 'if error happens keep going
- .
- .
- OPEN FileName$ FOR BINARY AS #1 'an error might happen here
- IF ERR THEN 'see if an error occured
- CALL ErrorHandler 'if so, go handle it
-
-
-
- The equivalent code in MAXLIB would be:
-
-
- FileNum% = OpenX%(FileName$) 'an error might happen here
- IF ErrorCode% THEN 'see if an error occured
- CALL ErrorHandler 'if so, go handle it
-
-
- It is important to realize that MAXLIB For PB won't handle
- errors for you. What MAXLIB For PB will do is trap the error
- and let you know which error it was. To handle errors actively,
- you must use an error handler in your program.
-
- The writing of an error handler is not difficult to understand.
- A typical error handler will consist of a SELECT CASE structure
- in which the various errors you anticipate are grouped according
- to the various messages you want to display or actions you want
- your program to take.
-
-
- SELECT CASE ErrorCode%
- CASE 2
- PRINT "File not found."
- CASE 3
- PRINT "Path not found."
- CASE 4
- .
- .
- CASE ELSE
- PRINT "Unknown error. Error code:"; ErrorCode%
- END SELECT
-
-
- At the very least, an error handler reports error codes along
- with descriptive messages. A more comprehensive error handler
- will allow your program the chance to resolve the error, or to
- shut down gracefully and save your data if possible.
-
-
-
-
-
- GENERAL TOPICS
-
-
- The following section covers several topics of general interest
- to programmers using MAXLIB For PB in their programs, including
- information about some problems you might encounter when using
- MAXLIB For PB, and how to avoid them.
-
-
-
-
- ABOUT FILE POINTERS
-
-
- It is possible to program in BASIC without ever learning about
- file pointers. However, MAXFiles requires that you understand
- file pointers, so if you are unfamiliar with them, please read
- this section.
-
- NOTE: DOS, PB and MAXFiles all consider a file's first byte to
- be byte zero rather than byte 1. Although MAXFiles does let you
- choose the one-based convention, this section will use the
- zero-based convention throughout.
-
- Think of a file pointer as an invisible finger pointing at the
- exact byte where MAXFiles will begin to read from or write to a
- file. It will move itself as you read (or write), like a finger
- following text on the page of a book. As you stop reading (or
- writing) the finger stops itself one byte beyond the last byte
- read (or written).
-
- When a file is first opened the pointer is at the first byte of
- the file: byte zero. If you start writing to a file right after
- opening it, you will start writing at byte zero. And if any
- data is in the file it will be overwritten by the new data,
- starting with byte zero.
-
- Luckily, you can move the pointer anywhere you want, anytime you
- want. For the sake of simplicity, let's suppose you have a file
- that is four bytes long and you want to append some data to the
- end of this file. The four bytes would run from zero to 3:
-
-
- BYTES: 0 1 2 3
- ^
-
- Since you have just opened the file, the pointer (^) is at byte
- zero. Before you can append data to the end of a file, the
- pointer must point one byte beyond the file's last byte. In
- this case the last byte is byte 3, and one byte beyond byte 3 is
- byte 4.
-
- To move a pointer for appending data, first you need to know how
- long the file is. In BASIC you could use LOF, but in MAXFiles
- you would use SizeX&, like so:
-
-
- Handle% = OpenX%(FileName$)
- Size& = SizeX&(Handle%)
-
-
- In this case, Size& will equal 4, because our file is four bytes
- long. And, conveniently, the byte that is one byte past the end
- is byte 4. You may move the pointer to byte 4, using SetLocX:
-
-
- Size& = SizeX&(Handle%) 'Size& = 4
- SetLocX Handle%, Size& 'pointer is at byte 4
-
-
- Now our file looks like this:
-
-
- BYTES: 0 1 2 3 (4)
- ^
-
- I put the 4 in parentheses because it really doesn't "belong to"
- our file yet, even though the pointer points there. Now, if we
- write something to our file, no old data will be overwritten.
-
- Now let's write some data to our file and see what happens. To
- write data, you can use PUT in BASIC. In MAXFiles you could use
- PutX. This is how you'd write an integer to the file:
-
-
- PutX Handle%, 2&, Variable%
-
-
- This writes 2 bytes to the end of our file, so it looks like
- this:
-
-
- BYTES: 0 1 2 3 4 5 (6)
- ^
-
- Now there are six bytes in our file (0-5) and the pointer has
- moved to byte 6. The pointer moves each time we write OR read
- bytes. It moves exactly one byte forward for every byte we read
- or write.
-
- Those last two sentences are VERY important:
-
- * The pointer moves each time you write OR read bytes. It moves
- exactly one byte forward for every byte you read or write. *
-
- If you do not know where the pointer is, you can get into big
- trouble. To avoid such trouble you can always ask where the
- pointer is by calling GetLocX&. Just remember that when
- GetLocX& tells you the pointer is at byte 1, it is referring to
- the second byte of the file.
-
- That covers all you need to know about file pointers. All in
- all, file pointers allow you to read or write anywhere you want
- in a file. You can open a file, read a few bytes, jump
- somewhere, write over some other bytes, jump to the end, tack on
- some bytes there, then jump back to the start - all without
- having to close and reopen your file.
-
- You are not required to having same-length records. You are not
- required to start at the front and plow straight to the end.
- You can order your data anyway you like and put it anywhere
- that's convenient, just by jumping the pointer there.
-
-
-
-
- ABOUT EXPANDED MEMORY
-
-
- This chapter gives you a quick overview of expanded memory and
- how it works. If you are already familiar with EMS, you may
- skip this section.
-
- The first verison of EMS was version 3.0. More precisely,
- versions prior to 3.0 were not made public. As of this writing,
- the EMS specification is in version 4.0 and it looks likely to
- stay there.
-
- All manipulation of EMS memory is accomplished through calls to
- an EMM driver, a piece of software loaded through CONFIG.SYS.
- Calls to the EMM driver are made through interrupt &H67. One
- common EMM driver is EMM386.SYS. It has been distributed with
- DOS since v5.0. Without a driver, EMS can't be used, even if it
- is installed.
-
- EMS requires that one 64K segment be set aside for its exclusive
- use, in the memory area starting at D000:0000 or E000:0000.
- This 64K segment is subdivided into 4 areas of 16K each,
- numbered 0-3. These areas are sometimes called "frames".
-
- To use expanded memory, you must allocate it first. Normally,
- EMS memory is allocated 16K bytes at a time. This is the method
- used by MAXLIB For PB. Each 16K chunk of memory is called a
- "page". It is no accident that pages and frames are the same
- size.
-
- You may allocate a group of many pages or just a single page.
- The group is assigned a handle, like a file handle. Most calls
- to the EMM driver require that you refer to this handle.
-
- The first page in a group is called page 0, the next is page 1,
- and so on. At the hardware level, no two pages in a single
- group need to be stored in contiguous memory. They can be
- scattered all over the physical address space of the EMS memory.
- But the driver takes care of that detail for you. As far you
- know, page 0 comes first, page 1 comes next. Sometimes
- ignorance is bliss!
-
- Before you can write to or read from any of the pages you have
- allocated, the page must first be "mapped" into a frame. This
- is done by calling the EMM driver. Once a page is mapped into a
- frame, the whole contents of the EMS page are copied into the
- memory that resides inside that frame. After this is done, any
- alteration to the memory inside the frame will be reflected in
- the memory of the page.
-
- Since only 4 frames exist, but a much larger number of pages may
- exist, pages generally must be shuffled in and out of these
- frames (a lot). This scheme is called "bank switching" and it
- has been around a long time.
-
- One peculiarity of EMS memory is the fact that it will not be
- deallocated as your program ends. Program memory (the famed
- first 640K) is automatically released by DOS when a program
- ends, unless the program is a TSR. But EMS memory remains
- allocated to the same handle until you actively deallocate it by
- calling the EMM driver.
-
- A program that allocates EMS and ends without releasing it, can
- effectively prevent any subsequent programs from using that EMS
- memory. To prevent this from happening in your programs, MAXLIB
- For PB will automatically deallocate all the EMS memory you have
- allocated with them, as your program ends. For more details
- about this, see ClearX and ClearEMS in MAXLIB.REF.
-
-
-
-
-
- ABOUT DOS STDXXX DEVICES
-
-
- Each time your computer boots, DOS opens a set of 5 handles,
- numbered 0-4. These handles are assigned to 5 standard devices.
- DOS uses these handles to access the devices for its own input
- and output. They are:
-
-
- Device: Handle: Initialized as:
- ------- ------- ---------------
- STDIN 0 Keyboard
- STDOUT 1 Screen
- STDERR 2 Screen
- STDAUX 3 Com port 1
- STDPRN 4 Printer (LPT1)
-
-
-
- Because MAXFiles uses the same handle-based services that DOS
- uses, you can take advantage of these STDxxx devices by passing
- their handles to the various MAXFiles routines.
-
- You should realize that using DOS devices can be a crude method
- of input and output. Only in a few situations will there be any
- advantage to using them, and in many cases there will be
- disadvantages. Most especially, I would NOT recommend using
- MAXFiles with STDAUX as a replacement for the built-in
- communications ability of PowerBASIC!
-
- However, two examples come quickly to mind where a STDxxx device
- has an advantage over using BASIC's own commands. One is where
- you want to direct your program's output through the ANSI.SYS
- device driver. The other is when you want to be able to
- redirect or pipe input or output from the command line.
-
- To output a string to the screen through DOS services, you could
- use BASIC code similar to this:
-
-
- OPEN "CONS:" FOR OUTPUT AS #1
- OutPut$ = "This will reach the screen via DOS."
- PRINT #1, OutPut$
-
-
- The MAXFiles equivalent would be this:
-
-
- %STDOUT = 1
- OutPut$ = "This will reach the screen via DOS."
- PutStX %STDOUT, OutPut$ + CHR$(13,10)
-
-
- In this example, OutPut$ would be (normally) be written to the
- screen by DOS. If DOS redirection were in effect, the string
- would be output to the device or file indicated by the
- redirection symbol on the command line, instead of to the
- screen.
-
- If OutPut$ included ANSI escape codes, routing OutPut$ through
- DOS makes it available to interpretation by ANSI.SYS.
-
- Most of the routines in MAXFiles will accept STDxxx handles,
- with two exceptions. CloseX will not close a handle numbered
- 0-4, and GetLineX$, because of its internal buffer and internal
- pointer, cannot accept a DOS device handle, either.
-
- Overall, if you require DOS redirection in your programs, you
- should be able to swing it, using just the routines in MAXFiles.
- But it may take some experimentation. For more information
- about DOS STDxxx devices, you should consult a good DOS
- reference.
-
-
-
-
- AVOIDING PROBLEMS WITH HUGE ARRAYS
-
-
- HUGE arrays are larger than a single 64K segment. PowerBASIC
- 3.0 lets you create HUGE arrays where the length of each element
- is not a power of two (the length is not 2,4,8,16...etc).
-
- To accomplish this feat the PowerBASIC compiler must recognize
- when the end of the current array segment does not contain
- enough bytes to hold a complete array element.
-
- Let's say you want to dimension an array of 1000 fixed length
- strings, where each string is 80 bytes long:
-
-
- DIM HUGE FixedStrings(1 TO 1000) AS STRING * 80
-
-
- The compiler can put 819 elements of 80 bytes each into the
- first 64K segment. At that point the segment contains 65520
- bytes of data with only 16 bytes left in the segment. That's
- not enough to hold a complete element, so the compiler will
- insert 16 "padding" bytes into the array at that point. This
- permits element 820 to start at a new 64K segment boundary.
-
- In PowerBASIC, placing a discontinuity like this into the data
- is not a problem, because array elements are always accessed
- individually.
-
- Unlike PowerBASIC, MAXLIB For PB has routines that allow you to
- access entire arrays all at once. These routines are GetX and
- PutX in MAXFiles, and ArrayInEMS and ArrayOutEMS in MAXArray.
-
- These commands always read data as a continuous series of bytes.
- If the compiler has stored the data in a discontinuous series of
- bytes, it causes problems. In our example using the fixed
- length string array, a discontinuity of 16 bytes occurs between
- elements 819 and 820.
-
- To demonstrate the problem more clearly, let's say you want to
- save a copy of that HUGE fixed length string array into a file,
- using PutX. It might seem natural to write code like this:
-
-
- FileName$ = "FIXSTRNG.DAT"
- SaveHandle% = OpenX%(FileName$) ' open a file to save into
-
- Bytes& = CLNG(80 * 1000) ' calculate bytes to save
- PutX SaveHandle%, Bytes&, FixedStrings(1) 'save them
-
-
- This code contains a bug. The problem comes in the third line,
- where we calculate how many bytes we need to write into the
- file.
-
- Yes, there are 80000 bytes of data to be read, but because of
- the 16 unused bytes that were inserted at the end of the first
- 64K segment, those 80000 bytes of data are stored across 80016
- bytes of memory!
-
- The bug comes in, because PutX is not smart enough to skip over
- the 16 bytes of non-data inserted into the array. Instead it
- will read those 16 bytes of padding into the file and it will
- not read the final 16 bytes of data.
-
- The easy way to work around this problem is to read each element
- individually, in a loop, and write each one to the file:
-
-
- FileName$ = "FIXSTRNG.DAT"
- SaveHandle% = OpenX%(FileName$) ' open a file to save into
-
- Bytes& = 80& ' read one element at a time
- FOR X% = 1 TO 1000
- PutX SaveHandle%, Bytes&, FixedStrings(X%)
- NEXT X%
-
-
- This is not the fastest solution possible, but it is by far the
- simplest. It is not the fastest because it requires your
- program to access the disk 1000 times, instead of once.
-
- Another possible work around is to make the disk file 80016
- bytes long, so it contains all the data, along with the gap in
- the data. Then you could load the resulting file directly into
- any HUGE array that is identical to the original array, because
- an identical array will have the same gap in the data, located
- in the same place!
-
- This last approach is rather inflexible, but it is certainly
- fast, since it uses the least number of disk reads or writes.
-
- If you are using ArrayInEMS and ArrayOutEMS instead of GetX and
- PutX, the range of solutions is even narrower. Simply put, you
- cannot use ArrayInEMS or ArrayOutEMS with any HUGE array that
- has an element size which is not a power of two. With such
- arrays, you must use InEMS and OutEMS one element at a time.
-
-
-
-
-
- SAFEGUARDING YOUR DATA
-
-
- This section is meant to help you to design your programs
- written with MAXLIB For PB to be as safe as possible. The major
- concern is that any data that is stored in EMS will disappear
- without a trace when the power turns off. In this respect
- expanded memory is just like conventional RAM.
-
- Data stored in EMS arrays using MAXArray should be considered to
- be as vulnerable as data kept in ordinary arrays. There are no
- ways to make it safer. With MAXFiles, however, there are some
- safeguards built in, and others you can add.
-
- Normally, as your program ends, MAXFiles ensures that every file
- you have opened is written safely to disk. However, power
- surges, frozen keyboards, critical errors and other disruptions
- do happen, and you should design your program around their
- possibility. This section tells you how.
-
- The first question you must ask is: how vital is this data? I
- can't answer that one for you. Among other things, you should
- consider whether the data can be reconstructed from existing
- data, and what portion of the data you could place at risk
- before the risk becomes unacceptable.
-
- The second question is: how can I make my data as safe as
- possible, using MAXFiles? I will try to answer that one.
-
- For files that absolutely MUST be written to a physical disk as
- quickly as possible, MAXFiles gives you the option of forcing a
- particular file to be opened as a disk file. The command for
- this is called SetDiskFile.
-
- When you call SetDiskFile with a non-zero value, the next file
- opened and all subsequent files will be disk files. To permit
- MAXFiles to open EMS files again, call SetDiskFile once more,
- passing it a zero value.
-
-
-
- SetDiskFile 1 'force disk-only
- Handle% = OpenX%("importnt.dat") 'open as a disk file
- SetDiskFile 0 'resume default setting
-
-
-
- There is another, less drastic tool you can use to safeguard
- important data, while preserving the speed and convenience of
- letting MAXFiles manage your files in EMS. It is called FlushX.
-
- When you call FlushX with the handle for an EMS file, FlushX
- will open a disk file and copy the entire current contents of
- that file from expanded memory onto disk. It does this very
- rapidly. Then the disk file is closed, which flushes the
- contents of any DOS buffers to disk as well.
-
- The drawback to FlushX is that writing an entire file to disk,
- even quite rapidly, is relatively slow. Calling FlushX every
- time data is added to a file will completely defeat the purpose
- for using EMS in the first place - speed. Such a strategy would
- be slower than simply opening a disk file and writing to it
- incrementally.
-
- A more successful strategy for using FlushX might be to call it
- at every 100th iteration of a loop. Or you could invoke ON
- TIMER and call it every time a certain interval had passed.
- Only you can decide how to use this tool. But it is there to be
- used if you need it.
-
- Bear in mind that these precautions are most applicable when a
- file has been opened as an EMS file. Because MAXFiles will
- function perfectly well on computers having no EMS, you may want
- to determine whether a particular file has been opened as an EMS
- file or a disk file.
-
- To see if a file was opened as an EMS file or a disk file,
- examine the handle passed back by OpenX%. A file stored in EMS
- will have a handle greater than 255. A disk file will have a
- handle less than 255.
-
-